package com.iias.communication.message.client;

import com.iias.common.util.log.LogUtils;
import com.iias.communication.domain.ServiceInfo;
import com.iias.communication.interfaces.ClientConnectionHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import org.slf4j.Logger;

import java.util.concurrent.TimeUnit;

public class CommunicationClient implements Runnable{

    private final static Logger log = LogUtils.getLogger();
    private ServiceInfo serviceInfo;

    private boolean status = false;


    private ClientConnectionHandler clientConnectionHandler;


    public CommunicationClient(ServiceInfo serviceInfo,ClientConnectionHandler clientConnectionHandler) {
        this.serviceInfo = serviceInfo;
        log.info(serviceInfo.toString());
        if (serviceInfo.getIp()==null||serviceInfo.getPort()==null
                ||serviceInfo.getMasterEnum()==null)throw new RuntimeException("客户端==>初始化失败");
        this.clientConnectionHandler = clientConnectionHandler;
        init();
    }

    private NioEventLoopGroup group = new NioEventLoopGroup();
    private Bootstrap bootstrap =  new Bootstrap();
    private ChannelFuture channelFuture = null;

    public ServiceInfo getServiceInfo() {
        return serviceInfo;
    }

    void init(){
        bootstrap.group(group);
        bootstrap.channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addFirst(new ChannelInboundHandlerAdapter() {
                    @Override
                    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                        super.channelInactive(ctx);
                        listener(channelFuture.channel());
                    }
                });
                pipeline.addLast("decoder", new ClientDecodeFilter())
                        .addLast("encoder", new ByteArrayEncoder())
                        .addLast("handler", new ClientHandler());
            }
        });
    }
    public void connect(){
        try {
            channelFutureInit();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 监听线程
     *
     * @param channel
     */
    public void listener(Channel channel){
        channel.eventLoop().schedule( new Runnable() {
            @Override
            public void run() {
                log.info("正在尝试重新连接--->"+serviceInfo.getIp()+":"+serviceInfo.getPort());
                connect();
            }
        }, 10, TimeUnit.SECONDS);
    }

    /**
     * 链接服务端
     */
    public void channelFutureInit(){
        try{
            channelFuture = bootstrap.connect(serviceInfo.getIp(), serviceInfo.getPort());
            channelFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (future.isSuccess()){
                        status = true;
                        log.info("服务端通信正常--->"+serviceInfo.getIp()+":"+serviceInfo.getPort());
                        if (clientConnectionHandler!=null)
                        clientConnectionHandler.clientChannel(channelFuture.channel());
                        return;
                    }else {
                        status = false;
                        log.info("服务端通信断开--->"+serviceInfo.getIp()+":"+serviceInfo.getPort());
                        if (clientConnectionHandler!=null)
                        clientConnectionHandler.clientDisconnect(channelFuture.channel());
                        listener(future.channel());
                    }
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        connect();
    }
}
